import sys
import support
import exceptions


class DuplicateFlagExplanation(exceptions.Exception): pass
class UnexplainedFlagError(exceptions.Exception): pass
class FlagParseError(exceptions.Exception): pass
class TaskArgumentParseError(exceptions.Exception): pass


class FlagManager(support.Singleton):
    
    def __init__(self):
        self.__explanations = {}
        self.__given_tossflag_names = set()
        self.__values = {}
        
        # process sys.argv
        self.parse(sys.argv[1:])
    
    def parse(self, args_or_string):
        
        # get the args list
        if isinstance(args_or_string, basestring):
            args = args_or_string.split()
        else:
            args = args_or_string
            
        # parse the args
        for arg in args:
            if arg.startswith("--"):
                if "=" in arg:
                    pieces = arg.split("=")
                    if len(pieces) != 2:
                        raise FlagParseError("unable to parse tossflag '%s'" % arg)
                    tossflag_name = pieces[0][2:]
                    self.add_name(tossflag_name)
                    self.add_value(tossflag_name, pieces[1])
                else:
                    tossflag_name = arg[2:]
                    self.add_name(tossflag_name)
        
    def get_explanation_for(self, tossflag_name):
        return self.__explanations.get(tossflag_name, None)
    
    def set_explanation_for(self, tossflag_name, explanation):
        self.__explanations[tossflag_name] = explanation
    
    def add_name(self, tossflag_name):
        self.__given_tossflag_names.add(tossflag_name)
    
    def add_value(self, tossflag_name, value):
        self.__values[tossflag_name] = value
    
    def was_given(self, tossflag_name):
        self._ensure_tossflag_was_explained(tossflag_name)
        return tossflag_name in self.__given_tossflag_names
    
    def value_for(self, tossflag_name):
        self._ensure_tossflag_was_explained(tossflag_name)
        return self.__values.get(tossflag_name, None)
    
    def get_all_explanations(self):
        return self.__explanations
    
    def _ensure_tossflag_was_explained(self, tossflag_name):
        if self.get_explanation_for(tossflag_name) == None:
            raise UnexplainedFlagError("you must explain your Flags before using them")


class Flag(object):
    
    name = property(lambda self: self.__name)
    explanation = property(lambda self: FlagManager.get_instance().get_explanation_for(self.name))
    given = property(lambda self: FlagManager.get_instance().was_given(self.name))
    value = property(lambda self: FlagManager.get_instance().value_for(self.name))
    
    def __init__(self, name):
        self.__name = name
    
    def explain(self, explanation):
        if self.explanation:
            raise DuplicateFlagExplanation("tried to explain the '%s' tossflag multiple times" % self.name)
        FlagManager.get_instance().set_explanation_for(self.__name, explanation)
